Some R packages we will be using for the workshop. Feel free to add
others during the session.
The dataset we will be using is the State Expenditures data set,
which you can load into your R session by passing the URL to
RSocrata::read.socrata().
This report provides information on expenditures (i.e., cash
transactions/payments) for the agencies that utilize the Statewide
Financial Management Application (SFMA) issued for the fiscal year 2024
(July 1, 2023 - June 30, 2024).
Viewing the data
We do not build an analysis around the data we have; we find the
data for the analysis that we need!
This chunk shows two ways we can load the data, one relies on an API
via RSocrata, whereas the second option relies on exporting the data
manually from Data.Oregon.Gov.
# Using RSocrata
state_expenditures <- read.socrata("https://data.oregon.gov/Revenue-Expense/Agency-Expenditures-Multi-Year-Report/y9g9-xsxs")
# Using csv file stored locally
#state_expenditures <- read.csv(here("data", "Agency_Expenditures_–_Multi-Year_Report_20250827.csv"), stringsAsFactors = FALSE)
glimpse(state_expenditures)
Rows: 567,728
Columns: 10
$ fiscal_year <int> 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 20…
$ agency <int> 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 9…
$ agency_1 <chr> "REAL ESTATE AGY", "REAL ESTATE AGY", "REAL ESTATE AGY", "REAL ESTATE AGY", "REAL ESTA…
$ budget_class <int> 3110, 3240, 4100, 4100, 4100, 4100, 4100, 4100, 4100, 4100, 4100, 4100, 4100, 4100, 41…
$ budget_class_1 <chr> "CLASS/UNCLASS SALARY & PER DIEM", "UNEMPLOYMENT ASSESSMENT", "INSTATE TRAVEL", "INSTA…
$ expend_class <int> 3111, 3231, 4101, 4101, 4101, 4101, 4101, 4104, 4105, 4106, 4106, 4108, 4108, 4108, 41…
$ expend_class_1 <chr> "REGULAR EMPLOYEES", "UNEMPLOYMENT COMPENSATION & ASSESSMENT", "INSTATE MEALS WITH OVE…
$ vendor <chr> "DEPARTMENT OF ADMINISTRATIVE SERVICES", "EMPLOYMENT DEPARTMENT", "FRANK LEONARD JR", …
$ expense <dbl> 270.72, 5131.00, 59.00, 73.75, 88.50, 295.00, 458.13, 120.00, 414.01, 898.28, 2843.22,…
$ vendor_st <chr> "OR", "OR", "", "", "", "", "", "MO", "MO", "", "MO", "", "", "", "", "", "OR", "MO", …
Data quality check
We’ll clean-up some of the types that should be treated as
characters. We’ll also rename variables for improved readability.
state_expenditures_clean <-
state_expenditures %>%
mutate(
agency = as.character(agency),
expend_class = as.character(expend_class),
budget_class = as.character(budget_class)
) %>%
rename(
"agency_code" = agency,
"agency_name" = agency_1,
"budget_class_code" = budget_class,
"buget_class_name" = budget_class_1,
"expend_class_code" = expend_class,
"expend_class_name" = expend_class_1
)
glimpse(state_expenditures_clean)
Rows: 567,728
Columns: 10
$ fiscal_year <int> 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023,…
$ agency_code <chr> "919", "919", "919", "919", "919", "919", "919", "919", "919", "919", "919", "919",…
$ agency_name <chr> "REAL ESTATE AGY", "REAL ESTATE AGY", "REAL ESTATE AGY", "REAL ESTATE AGY", "REAL E…
$ budget_class_code <chr> "3110", "3240", "4100", "4100", "4100", "4100", "4100", "4100", "4100", "4100", "41…
$ buget_class_name <chr> "CLASS/UNCLASS SALARY & PER DIEM", "UNEMPLOYMENT ASSESSMENT", "INSTATE TRAVEL", "IN…
$ expend_class_code <chr> "3111", "3231", "4101", "4101", "4101", "4101", "4101", "4104", "4105", "4106", "41…
$ expend_class_name <chr> "REGULAR EMPLOYEES", "UNEMPLOYMENT COMPENSATION & ASSESSMENT", "INSTATE MEALS WITH …
$ vendor <chr> "DEPARTMENT OF ADMINISTRATIVE SERVICES", "EMPLOYMENT DEPARTMENT", "FRANK LEONARD JR…
$ expense <dbl> 270.72, 5131.00, 59.00, 73.75, 88.50, 295.00, 458.13, 120.00, 414.01, 898.28, 2843.…
$ vendor_st <chr> "OR", "OR", "", "", "", "", "", "MO", "MO", "", "MO", "", "", "", "", "", "OR", "MO…
We can use inspectdf to view the unique counts, and most
common values for each of the categorical variables.
state_expenditures_clean %>%
inspect_cat()
Column (2/8): agency_name
Column (3/8): budget_class_code
Column (4/8): buget_class_name
Column (5/8): expend_class_code
Column (6/8): expend_class_name
Column (7/8): vendor
Column (8/8): vendor_st
We can see that there are discrepancies between the agency, budget,
and expenditure class codes since the total counts for these are
different. Let’s take a look at those.
state_expenditures_clean %>%
distinct(agency_code, agency_name) %>%
count(agency_code, sort = TRUE) %>%
filter(n > 1)
state_expenditures_clean %>%
distinct(budget_class_code, buget_class_name) %>%
count(budget_class_code, sort = TRUE) %>%
filter(n > 1)
state_expenditures_clean %>%
distinct(expend_class_code, expend_class_name) %>%
count(expend_class_code, sort = TRUE) %>%
filter(n > 1)
At this point we may decide that the data quality issues require
engagement with the data owners of this asset to proceed with our
analysis.
Or we may be comfortable with proceeding!
Exploratory Analysis
Viewing total expenses by year
state_expenditures_clean %>%
group_by(fiscal_year) %>%
reframe(total_expenses_in_billions = sum(expense)/1e9)
state_expenditures_clean %>%
group_by(fiscal_year) %>%
reframe(total_expenses_in_billions = sum(expense)/1e9) %>%
ggplot(aes(x = as.factor(fiscal_year), y = total_expenses_in_billions)) +
geom_col() +
scale_y_continuous(labels = scales::label_currency()) +
theme_classic() +
labs(
y = "Total Expenses ($ Billions)",
x = NULL,
caption = "\nData source:\n \'Agency Expenditures - Multi-Year Report\'\n As of December 17, 2024 from Data.Oregon.Gov"
)

How about viewing by agencies with the top 5 highest expenses in
2019?
top_agencies <-
state_expenditures_clean %>%
filter(fiscal_year == 2024) %>%
group_by(agency_name) %>%
reframe(total_expenses = sum(expense)) %>%
arrange(-total_expenses) %>%
slice(1:5) %>%
pull(agency_name)
summary_by_top_agencies <-
state_expenditures_clean %>%
filter(agency_name %in% top_agencies) %>%
group_by(fiscal_year, agency_name) %>%
reframe(total_expenses_in_billions = sum(expense)/1e9) %>%
mutate(
agency_name = fct_reorder(agency_name, total_expenses_in_billions, .desc = TRUE)
)
summary_by_top_agencies %>%
ggplot(aes(x = as.factor(fiscal_year), y = total_expenses_in_billions, group = agency_name)) +
geom_col() +
facet_wrap(~ agency_name, ncol = 3, scales = "free_y", axes = "margins") +
scale_y_continuous(labels = scales::label_currency()) +
theme_classic() +
labs(
y = "Total Expenses ($ Billions)",
x = NULL,
caption = "\nData source:\n \'Agency Expenditures - Multi-Year Report\'\n As of December 17, 2024 from Data.Oregon.Gov",
title = "Agencies with the Top Highest Expenditures in 2024",
subtitle = "Axes for total expenses varies by agency to show differences in scale."
)

8.27.2025
Amelia L. Vargas
LS0tDQp0aXRsZTogIlNPUkEgSW5jbHVzaXZlIEFuYWx5dGljcyBXb3Jrc2hvcCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNClNvbWUgUiBwYWNrYWdlcyB3ZSB3aWxsIGJlIHVzaW5nIGZvciB0aGUgd29ya3Nob3AuIEZlZWwgZnJlZSB0byBhZGQgb3RoZXJzIGR1cmluZyB0aGUgc2Vzc2lvbi4gDQoNCmBgYHtyIHNldHVwfQ0KbGlicmFyeShoZXJlKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoUlNvY3JhdGEpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGluc3BlY3RkZikNCmxpYnJhcnkoZm9yY2F0cykNCmBgYA0KDQpUaGUgZGF0YXNldCB3ZSB3aWxsIGJlIHVzaW5nIGlzIHRoZSBTdGF0ZSBFeHBlbmRpdHVyZXMgZGF0YSBzZXQsIHdoaWNoIHlvdSBjYW4gbG9hZCBpbnRvIHlvdXIgUiBzZXNzaW9uIGJ5IHBhc3NpbmcgdGhlIFVSTCB0byBgUlNvY3JhdGE6OnJlYWQuc29jcmF0YSgpYC4gDQoNCkFib3V0IHRoZSBkYXRhOiANCjxodHRwczovL2RhdGEub3JlZ29uLmdvdi9SZXZlbnVlLUV4cGVuc2UvQWdlbmN5LUV4cGVuZGl0dXJlcy1NdWx0aS1ZZWFyLVJlcG9ydC95OWc5LXhzeHMvYWJvdXRfZGF0YT4NCg0KVGhpcyByZXBvcnQgcHJvdmlkZXMgaW5mb3JtYXRpb24gb24gZXhwZW5kaXR1cmVzIChpLmUuLCBjYXNoIHRyYW5zYWN0aW9ucy9wYXltZW50cykgZm9yIA0KdGhlIGFnZW5jaWVzIHRoYXQgdXRpbGl6ZSB0aGUgU3RhdGV3aWRlIEZpbmFuY2lhbCBNYW5hZ2VtZW50IEFwcGxpY2F0aW9uIChTRk1BKSBpc3N1ZWQgDQpmb3IgdGhlIGZpc2NhbCB5ZWFyIDIwMjQgKEp1bHkgMSwgMjAyMyAtIEp1bmUgMzAsIDIwMjQpLiANCg0KIyBQdXJwb3NlDQoNCkJlZm9yZSBkZWZpbmluZyBvdXIgcHVycG9zZSB3ZSBzaG91bGQgY29uc2lkZXIuLi4gDQoNCiMjIFdobyBtaWdodCBiZSBpbnRlcmVzdGVkIGluIGFuIGFuYWx5c2lzIG9mIGV4cGVuZGl0dXJlcz8gDQoNCiogUHVibGljIGVtcGxveWVlcyAgDQoqIEFnZW5jaWVzL2FnZW5jeSBoZWFkcyAgDQoqIFB1YmxpYy90YXhwYXllcnMgIA0KKiBMZWdpc2xhdG9ycyAgDQoqIFZlbmRvcnMvU3VwcGxpZXJzICANCiogQXVkaXRvcnMgIA0KKiBBbmFseXN0cw0KDQoNCiMjIFdoYXQgYXJlIHRoZSBiZW5lZml0cz8NCg0KKiBQcm9jZXNzIGltcHJvdmVtZW50cyAoaW50ZXJuYWwgYW5kIGV4dGVybmFsKSAgDQoqIFZpZXdpbmcgb3V0bGllcnMgKGlkZW50aWZ5aW5nIHRvbyBzbWFsbCBvciB0b28gbGFyZ2Ugb2YgZXhwZW5kaXR1cmVzKSANCiogVHJlbmRzLCBlLmcuIHNlZWluZyB0aGUgZ2VuZXJhbCBwYXR0ZXJuIC0gd2hhdCBhcmUgdGhlIGhpZ2hlc3QvbG93ZXN0IGV4cGVuZGl0dXJlcywgd2hhdCBhcmUgdGhlIG1vc3QgY29tbW9uIGV4cGVuc2VzLCBldGMuDQoqIENvbXBsaWFuY2UsIHRvIGVuc3VyZSB0aGF0IHdlIGFyZSBmb2xsb3dpbmcgb3VyIHByb2N1cmVtZW50IHJ1bGVzDQoqIE9wcG9ydHVuaXRpZXMgZm9yIGNvbnNvbGlkYXRpbmcsIGdldHRpbmcgYmV0dGVyIGNvbnRyYWN0cw0KKiBCZXR0ZXIgdW5kZXJzdGFuZGluZyBvZiB3aGVyZSB0YXhlcyBnbw0KDQojIyBXaGF0IGFyZSB0aGUgcmlza3M/IA0KDQoqIExlZ2lzbGF0b3JzIG1heSBzZWUgdGhlIGFuYWx5c2lzIGFuZCB0aGluayB0aGF0IGNvc3RzIGFyZSB0b28gaGlnaCBhbmQgdXNlIGl0IGFzIHJhdGlvbmFsZSB0byBjdXQgYnVkZ2V0cyAgDQoqIFBhdHRlcm5zIG1heSBiZSByZXZlYWxlZCB0aGF0IGhhcm0gcmVwdXRhdGlvbnMgKGluc3RpdHV0aW9uYWwsIGluZGl2aWR1YWwsIGV0YykNCg0KUHVycG9zZTogDQpNYWtlIHRoZSBleHBlbmRpdHVyZXMgZGF0YSBzZXQgbW9yZSBhY2Nlc3NpYmxlIHRvIHRob3NlIGludGVyZXN0ZWQgaW4gdGhlIGFuYWx5c2lzIGJ5IHByb3ZpZGluZw0KDQpFeHBlbnNlIHRyZW5kcyAgDQoNCiogT3ZlcmFsbCBleHBlbnNlcyBieSB5ZWFyICANCiogRXhwZW5zZSBieSB5ZWFyIGJ5IGFnZW5jeSAgDQoqIEV4cGVuc2UgYnkgY2F0ZWdvcnkgYnkgYWdlbmN5ICANCiogRXhwZW5zZSBieSBjYXRlZ29yeSBieSB2ZW5kb3IgIA0KDQpEZWVwIGRpdmUgaW50byBvdXRsaWVycyAgDQoNCiogSGlnaCAmIExvdyBleHBlbmRpdHVyZXMgIA0KKiBFeHBlbnNlcyBvdXQgb2YgY29tcGxpYW5jZSB3aXRoIHByb2N1cmVtZW50IHN0YXR1ZXMvcnVsZXMvZ3VpZGFuY2UNCg0KIyBWaWV3aW5nIHRoZSBkYXRhICANCg0KKldlIGRvIG5vdCBidWlsZCBhbiBhbmFseXNpcyBhcm91bmQgdGhlIGRhdGEgd2UgaGF2ZTsgd2UgZmluZCB0aGUgZGF0YSBmb3IgdGhlIGFuYWx5c2lzIHRoYXQgd2UgbmVlZCEqDQoNClRoaXMgY2h1bmsgc2hvd3MgdHdvIHdheXMgd2UgY2FuIGxvYWQgdGhlIGRhdGEsIG9uZSByZWxpZXMgb24gYW4gQVBJIHZpYSBSU29jcmF0YSwgd2hlcmVhcyB0aGUgc2Vjb25kIG9wdGlvbiByZWxpZXMgb24gZXhwb3J0aW5nIHRoZSBkYXRhIG1hbnVhbGx5IGZyb20gDQpEYXRhLk9yZWdvbi5Hb3YuDQoNCmBgYHtyIGxvYWQtZXhwZW5kaXR1cmUtZGF0YSwgZWNobz1UUlVFfQ0KIyBVc2luZyBSU29jcmF0YQ0Kc3RhdGVfZXhwZW5kaXR1cmVzIDwtIHJlYWQuc29jcmF0YSgiaHR0cHM6Ly9kYXRhLm9yZWdvbi5nb3YvUmV2ZW51ZS1FeHBlbnNlL0FnZW5jeS1FeHBlbmRpdHVyZXMtTXVsdGktWWVhci1SZXBvcnQveTlnOS14c3hzIikNCg0KIyBVc2luZyBjc3YgZmlsZSBzdG9yZWQgbG9jYWxseQ0KI3N0YXRlX2V4cGVuZGl0dXJlcyA8LSByZWFkLmNzdihoZXJlKCJkYXRhIiwgIkFnZW5jeV9FeHBlbmRpdHVyZXNf4oCTX011bHRpLVllYXJfUmVwb3J0XzIwMjUwODI3LmNzdiIpLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQoNCmdsaW1wc2Uoc3RhdGVfZXhwZW5kaXR1cmVzKQ0KYGBgDQojIyBEYXRhIHF1YWxpdHkgY2hlY2sNCg0KV2UnbGwgY2xlYW4tdXAgc29tZSBvZiB0aGUgdHlwZXMgdGhhdCBzaG91bGQgYmUgdHJlYXRlZCBhcyBjaGFyYWN0ZXJzLiBXZSdsbCBhbHNvIHJlbmFtZSB2YXJpYWJsZXMgZm9yIGltcHJvdmVkIHJlYWRhYmlsaXR5Lg0KDQpgYGB7ciBlY2hvPVRSVUV9DQpzdGF0ZV9leHBlbmRpdHVyZXNfY2xlYW4gPC0gDQogIHN0YXRlX2V4cGVuZGl0dXJlcyAlPiUgDQogIG11dGF0ZSgNCiAgICBhZ2VuY3kgPSBhcy5jaGFyYWN0ZXIoYWdlbmN5KSwNCiAgICBleHBlbmRfY2xhc3MgPSBhcy5jaGFyYWN0ZXIoZXhwZW5kX2NsYXNzKSwNCiAgICBidWRnZXRfY2xhc3MgPSBhcy5jaGFyYWN0ZXIoYnVkZ2V0X2NsYXNzKQ0KICApICU+JSANCiAgcmVuYW1lKA0KICAgICJhZ2VuY3lfY29kZSIgPSBhZ2VuY3ksDQogICAgImFnZW5jeV9uYW1lIiA9IGFnZW5jeV8xLA0KICAgICJidWRnZXRfY2xhc3NfY29kZSIgPSBidWRnZXRfY2xhc3MsDQogICAgImJ1Z2V0X2NsYXNzX25hbWUiID0gYnVkZ2V0X2NsYXNzXzEsDQogICAgImV4cGVuZF9jbGFzc19jb2RlIiA9IGV4cGVuZF9jbGFzcywNCiAgICAiZXhwZW5kX2NsYXNzX25hbWUiID0gZXhwZW5kX2NsYXNzXzENCiAgKQ0KDQpnbGltcHNlKHN0YXRlX2V4cGVuZGl0dXJlc19jbGVhbikNCmBgYA0KV2UgY2FuIHVzZSBgaW5zcGVjdGRmYCB0byB2aWV3IHRoZSB1bmlxdWUgY291bnRzLCBhbmQgbW9zdCBjb21tb24gdmFsdWVzIGZvciBlYWNoIG9mIHRoZSBjYXRlZ29yaWNhbCB2YXJpYWJsZXMuIA0KDQpgYGB7ciBlY2hvPVRSVUV9DQpzdGF0ZV9leHBlbmRpdHVyZXNfY2xlYW4gJT4lIA0KICBpbnNwZWN0X2NhdCgpDQpgYGANCg0KV2UgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSBkaXNjcmVwYW5jaWVzIGJldHdlZW4gdGhlIGFnZW5jeSwgYnVkZ2V0LCBhbmQgZXhwZW5kaXR1cmUgY2xhc3MgY29kZXMgc2luY2UgdGhlIHRvdGFsIGNvdW50cyBmb3IgdGhlc2UgYXJlIGRpZmZlcmVudC4gDQpMZXQncyB0YWtlIGEgbG9vayBhdCB0aG9zZS4gDQoNCmBgYHtyIGlkZW50aWZ5LWR1cGxpY2F0ZXMsIGVjaG89VFJVRX0NCnN0YXRlX2V4cGVuZGl0dXJlc19jbGVhbiAlPiUgDQogIGRpc3RpbmN0KGFnZW5jeV9jb2RlLCBhZ2VuY3lfbmFtZSkgJT4lIA0KICBjb3VudChhZ2VuY3lfY29kZSwgc29ydCA9IFRSVUUpICU+JSANCiAgZmlsdGVyKG4gPiAxKQ0KDQoNCnN0YXRlX2V4cGVuZGl0dXJlc19jbGVhbiAlPiUgDQogIGRpc3RpbmN0KGJ1ZGdldF9jbGFzc19jb2RlLCBidWdldF9jbGFzc19uYW1lKSAlPiUgDQogIGNvdW50KGJ1ZGdldF9jbGFzc19jb2RlLCBzb3J0ID0gVFJVRSkgJT4lIA0KICBmaWx0ZXIobiA+IDEpDQoNCg0Kc3RhdGVfZXhwZW5kaXR1cmVzX2NsZWFuICU+JSANCiAgZGlzdGluY3QoZXhwZW5kX2NsYXNzX2NvZGUsIGV4cGVuZF9jbGFzc19uYW1lKSAlPiUgDQogIGNvdW50KGV4cGVuZF9jbGFzc19jb2RlLCBzb3J0ID0gVFJVRSkgJT4lIA0KICBmaWx0ZXIobiA+IDEpDQpgYGANCg0KDQpBdCB0aGlzIHBvaW50IHdlIG1heSBkZWNpZGUgdGhhdCB0aGUgZGF0YSBxdWFsaXR5IGlzc3VlcyByZXF1aXJlIGVuZ2FnZW1lbnQgd2l0aCB0aGUgZGF0YSBvd25lcnMgb2YgdGhpcyBhc3NldCB0byBwcm9jZWVkIHdpdGggb3VyIGFuYWx5c2lzLiANCg0KT3Igd2UgbWF5IGJlIGNvbWZvcnRhYmxlIHdpdGggcHJvY2VlZGluZyENCg0KIyBFeHBsb3JhdG9yeSBBbmFseXNpcw0KDQpWaWV3aW5nIHRvdGFsIGV4cGVuc2VzIGJ5IHllYXINCg0KYGBge3IgZWNobz1UUlVFfQ0Kc3RhdGVfZXhwZW5kaXR1cmVzX2NsZWFuICU+JSANCiAgZ3JvdXBfYnkoZmlzY2FsX3llYXIpICU+JSANCiAgcmVmcmFtZSh0b3RhbF9leHBlbnNlc19pbl9iaWxsaW9ucyA9IHN1bShleHBlbnNlKS8xZTkpDQpgYGANCg0KYGBge3IgZWNobz1UUlVFfQ0Kc3RhdGVfZXhwZW5kaXR1cmVzX2NsZWFuICU+JSANCiAgZ3JvdXBfYnkoZmlzY2FsX3llYXIpICU+JSANCiAgcmVmcmFtZSh0b3RhbF9leHBlbnNlc19pbl9iaWxsaW9ucyA9IHN1bShleHBlbnNlKS8xZTkpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gYXMuZmFjdG9yKGZpc2NhbF95ZWFyKSwgeSA9IHRvdGFsX2V4cGVuc2VzX2luX2JpbGxpb25zKSkgKyANCiAgZ2VvbV9jb2woKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX2N1cnJlbmN5KCkpICsNCiAgdGhlbWVfY2xhc3NpYygpICsgDQogIGxhYnMoDQogICAgeSA9ICJUb3RhbCBFeHBlbnNlcyAoJCBCaWxsaW9ucykiLCANCiAgICB4ID0gTlVMTCwNCiAgICBjYXB0aW9uID0gIlxuRGF0YSBzb3VyY2U6XG4gXCdBZ2VuY3kgRXhwZW5kaXR1cmVzIC0gTXVsdGktWWVhciBSZXBvcnRcJ1xuIEFzIG9mIERlY2VtYmVyIDE3LCAyMDI0IGZyb20gRGF0YS5PcmVnb24uR292Ig0KICApDQpgYGANCg0KDQpIb3cgYWJvdXQgdmlld2luZyBieSBhZ2VuY2llcyB3aXRoIHRoZSB0b3AgNSBoaWdoZXN0IGV4cGVuc2VzIGluIDIwMTk/IA0KDQpgYGB7ciBlY2hvPVRSVUV9DQp0b3BfYWdlbmNpZXMgPC0gDQogIHN0YXRlX2V4cGVuZGl0dXJlc19jbGVhbiAlPiUgDQogIGZpbHRlcihmaXNjYWxfeWVhciA9PSAyMDI0KSAlPiUgDQogIGdyb3VwX2J5KGFnZW5jeV9uYW1lKSAlPiUgDQogIHJlZnJhbWUodG90YWxfZXhwZW5zZXMgPSBzdW0oZXhwZW5zZSkpICU+JSANCiAgYXJyYW5nZSgtdG90YWxfZXhwZW5zZXMpICU+JSANCiAgc2xpY2UoMTo1KSAlPiUgDQogIHB1bGwoYWdlbmN5X25hbWUpDQoNCnN1bW1hcnlfYnlfdG9wX2FnZW5jaWVzIDwtIA0KICBzdGF0ZV9leHBlbmRpdHVyZXNfY2xlYW4gJT4lIA0KICBmaWx0ZXIoYWdlbmN5X25hbWUgJWluJSB0b3BfYWdlbmNpZXMpICU+JSANCiAgZ3JvdXBfYnkoZmlzY2FsX3llYXIsIGFnZW5jeV9uYW1lKSAlPiUgDQogIHJlZnJhbWUodG90YWxfZXhwZW5zZXNfaW5fYmlsbGlvbnMgPSBzdW0oZXhwZW5zZSkvMWU5KSAlPiUgDQogIG11dGF0ZSgNCiAgICBhZ2VuY3lfbmFtZSA9IGZjdF9yZW9yZGVyKGFnZW5jeV9uYW1lLCB0b3RhbF9leHBlbnNlc19pbl9iaWxsaW9ucywgLmRlc2MgPSBUUlVFKQ0KICApDQogIA0Kc3VtbWFyeV9ieV90b3BfYWdlbmNpZXMgICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gYXMuZmFjdG9yKGZpc2NhbF95ZWFyKSwgeSA9IHRvdGFsX2V4cGVuc2VzX2luX2JpbGxpb25zLCBncm91cCA9IGFnZW5jeV9uYW1lKSkgKyANCiAgZ2VvbV9jb2woKSArDQogIGZhY2V0X3dyYXAofiBhZ2VuY3lfbmFtZSwgbmNvbCA9IDMsIHNjYWxlcyA9ICJmcmVlX3kiLCBheGVzID0gIm1hcmdpbnMiKSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpsYWJlbF9jdXJyZW5jeSgpKSArDQogIHRoZW1lX2NsYXNzaWMoKSArIA0KICBsYWJzKA0KICAgIHkgPSAiVG90YWwgRXhwZW5zZXMgKCQgQmlsbGlvbnMpIiwgDQogICAgeCA9IE5VTEwsDQogICAgY2FwdGlvbiA9ICJcbkRhdGEgc291cmNlOlxuIFwnQWdlbmN5IEV4cGVuZGl0dXJlcyAtIE11bHRpLVllYXIgUmVwb3J0XCdcbiBBcyBvZiBEZWNlbWJlciAxNywgMjAyNCBmcm9tIERhdGEuT3JlZ29uLkdvdiIsDQogICAgdGl0bGUgPSAiQWdlbmNpZXMgd2l0aCB0aGUgVG9wIEhpZ2hlc3QgRXhwZW5kaXR1cmVzIGluIDIwMjQiLA0KICAgIHN1YnRpdGxlID0gIkF4ZXMgZm9yIHRvdGFsIGV4cGVuc2VzIHZhcmllcyBieSBhZ2VuY3kgdG8gc2hvdyBkaWZmZXJlbmNlcyBpbiBzY2FsZS4iDQogICkNCmBgYA0KDQo4LjI3LjIwMjUgIA0KQW1lbGlhIEwuIFZhcmdhcw==